package org.jordens.jdbcspy.jmx;

import java.io.*;

/**
 * A simple object wrapping various query-related statistics.
 *
 * Thread-safety should be considered the responsibility of the users of this class.
 * No attention has been taken to ensure that attributes are updated in a thread-safe
 * manner.
 *
 * @author Adam Jordens
 */
public class QueryStatistic implements Comparable<QueryStatistic>, Serializable
{
    /** SQL executed */
    private final String sql;

    /** Total # of milliseconds spent in execution */
    private Long ms;

    /** # of executions */
    private Long count = 1L;

    /** Time of first execution (in ms since 1970) */
    private long firstExecution = 0;

    /** Time of last execution (in ms since 1970) */
    private long lastExecution = 0;

    /**
     * @param sql SQL executed
     * @param ms Execution time (milliseconds)
     */
    QueryStatistic(String sql, long ms)
    {
        this.sql = sql;
        this.ms = ms;
        this.firstExecution = System.currentTimeMillis();
        this.lastExecution = firstExecution;
    }

    /**
     * @param sql SQL executed
     * @param ms Execution time (milliseconds)
     * @param firstExecution First execution time (milliseconds)
     */
    public QueryStatistic(String sql, long ms, long firstExecution)
    {
        this.sql = sql;
        this.ms = ms;
        this.firstExecution = firstExecution;
        this.lastExecution = firstExecution;
    }

    /**
     * Copy constructor.
     *
     * @param queryStatistic QueryStatistic that will be copied. 
     */
    public QueryStatistic(QueryStatistic queryStatistic)
    {
        this.sql = queryStatistic.getSql();
        this.ms = queryStatistic.getSQLExecutionTime();
        this.firstExecution = queryStatistic.getFirstExecution();
        this.lastExecution = queryStatistic.getLastExecution();
        this.count = queryStatistic.getCount();
    }

    /**
     * @param ms Execution time (milliseconds)
     */
    public void record(long ms)
    {
        this.ms += ms;
        this.count++;
        this.lastExecution = System.currentTimeMillis();
    }

    /**
     * @return # of times this query has been executed
     */
    public long getCount()
    {
        return count;
    }

    /**
     * @return First time this query was executed (in ms)
     */
    public long getFirstExecution()
    {
        return firstExecution;
    }

    /**
     * @return Last time this query was executed (in ms)
     */
    public long getLastExecution()
    {
        return lastExecution;
    }

    /**
     * @return Amount of time spent executing this sql (in ms)
     */
    public long getSQLExecutionTime()
    {
        return ms;
    }

    /**
     * Getter for property 'sql'.
     *
     * @return Value for property 'sql'.
     */
    public String getSql()
    {
        return sql;
    }

    /**
     * {@inheritDoc}
     */
    public String toString()
    {
        StringBuilder builder = new StringBuilder("[executions=");
        builder.append(count);
        builder.append(",time=");
        builder.append(ms);
        builder.append("ms] ");
        builder.append(sql);
        builder.append("\n");

        return builder.toString();
    }

    /**
     * {@inheritDoc}
     */
    public int compareTo(QueryStatistic queryStatistic)
    {
        int compareTo = queryStatistic.ms.compareTo(this.ms);
        if (compareTo == 0)
        {
            compareTo = queryStatistic.count.compareTo(this.count);
        }

        return compareTo;
    }
}
